/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ceair.flight.refund.service.uatp.impl;

import com.alibaba.dubbo.common.utils.Assert;

import com.ceair.flight.refund.dto.appmoblie.RefundApplyDto;
import com.ceair.flight.refund.dto.appmoblie.RefundTaxDto;
import com.ceair.flight.refund.dto.appmoblie.RefundTktDto;
import com.ceair.flight.refund.dto.external.PayDto;
import com.ceair.flight.refund.dto.external.PayProductDto;
import com.ceair.flight.refund.location.dt.enums.PaymentStatusEnum;
import com.ceair.flight.refund.location.dt.enums.RefundStatusEnum;
import com.ceair.flight.refund.location.model.FlightOrderDO;
import com.ceair.flight.refund.service.external.IOrderOperation;
import com.ceair.flight.refund.service.external.ITicketOperation;
import com.ceair.flight.refund.service.external.TktRfFormRes;
import com.ceair.flight.refund.service.uatp.IPayQueryService;
import com.ceair.flight.refund.service.uatp.ITktRefundNoGenerator;
import com.ceair.muibe.provider.tkt.CreateTktRefundFormReq;
import com.ceair.muibe.provider.tkt.RefundTktForm;
import com.ceair.muibe.provider.tkt.Tax;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 *
 * @author youguilin
 */
@Service
public class TktRefundNoGeneratorImpl implements ITktRefundNoGenerator {

    private static final Logger LOG = LoggerFactory.getLogger(TktRefundNoGeneratorImpl.class);
    @Autowired
    private ITicketOperation ticketOperation;
    @Autowired
    private IPayQueryService iPayQueryService;

    @Autowired
    private IOrderOperation orderOperation;

    @Override
    public TktRfFormRes generateRefundNo(RefundApplyDto entity) {
        CreateTktRefundFormReq req = getGenFormNoRequest(entity);
        return ticketOperation.crRefundForm(req);
    }

    @Override
    public TktRfFormRes generateRefundNo(RefundApplyDto entity, String card) {
        CreateTktRefundFormReq req = getGenFormNoRequest(entity);
        RefundTktForm refundTktForm = req.getRefundTktForm();
        refundTktForm.setPayMethod("TC");
        refundTktForm.setCreditcard("TP" + card);
        return ticketOperation.crRefundForm(req);
    }

    private CreateTktRefundFormReq getGenFormNoRequest(RefundApplyDto entity) {
        if (!checkRefundApplyStatus(entity)) {
            LOG.warn("Refund apply '{}' status '{}' is not valid for generating refund number", entity.getId(), entity.getStatus());
            throw new IllegalStateException("Refund apply status is not valid for generating refund number");
        }
        CreateTktRefundFormReq req = buildReq(entity);
        final String tktNo = req.getRefundTktForm().getTktNo();
        RefundTktDto refundTkt = entity.getRefundTkt();
        //设置channel code
        ticketOperation.setChannelCode(tktNo, refundTkt.getChannelNo());
        return req;
    }

    /**
     * 检查申请单是否符合生成退票单条件, 目前仅检查申请单状态是否是二审通过
     */
    private boolean checkRefundApplyStatus(RefundApplyDto entity) {
        String status = entity.getStatus();
        LOG.info("Checking refund apply status {}", status);
        RefundStatusEnum refundStatus = RefundStatusEnum.getByCode(status);
        return refundStatus != null && (RefundStatusEnum.SECOND_AUDIT_PASS == refundStatus
                || RefundStatusEnum.GENERATE_REFUND_NO_EXCEPTION == refundStatus
                || RefundStatusEnum.WAITING_CARD_FOR_REFUND_NO == refundStatus);
    }

    private CreateTktRefundFormReq buildReq(RefundApplyDto entity) {
        LOG.info("Building generate refund ticket No request with refund apply entity");
        Assert.notNull(entity, "Argument refund apply is null");
        CreateTktRefundFormReq req = new CreateTktRefundFormReq();
        RefundTktDto refundTkt = entity.getRefundTkt();
        Assert.notNull(refundTkt, "No refund ticket found in refund apply");
        String tktType = refundTkt.getTicketType();
        String currency = entity.getCurrency();
        //只要支付货币不是CNY就一定是国际票
        if (!"CNY".equalsIgnoreCase(currency)) {
            tktType = "I";
        }
        LOG.debug("Ticket type : {}", tktType);
        req.setTktType(tktType);
        RefundTktForm refundTktForm = buildRefundTktForm(entity);
        req.setRefundTktForm(refundTktForm);
        //20190110修改获取curreny方式
        String currencyCD = "";
        currencyCD = getPayMethod(refundTkt.getFlightOrderNo());
        if (StringUtils.isEmpty(currencyCD)){
            currencyCD = getPayCurrency(refundTkt.getFlightOrderNo());
        }
        req.setCurrency(currencyCD);
        return req;
    }

    public String getPayCurrency(String flightOrderNo) {
        FlightOrderDO flightOrderDO = orderOperation.getFlightOrderDetail(flightOrderNo);
        if (flightOrderDO == null){
            return "";
        }
        String oldNo = flightOrderDO.getOldRecId();
        if (StringUtils.isEmpty(oldNo)){
            return "";
        }
        String currencyCD = getPayMethod(oldNo);
        if (!StringUtils.isEmpty(currencyCD)){
            return currencyCD;
        }
        return getPayCurrency(oldNo);
    }

    private RefundTktForm buildRefundTktForm(RefundApplyDto entity) {
        RefundTktDto refundTkt = entity.getRefundTkt();
        RefundTktForm refundTktForm = new RefundTktForm();
        String currency = entity.getCurrency();
        LOG.debug("currency : {}-2", currency);
        refundTktForm.setCurrency(currency + "-2");//-2 是精度
        String ticketNo = refundTkt.getTicketNo();
        LOG.debug("ticketNo : {}", ticketNo);
        String airlineCode = getAirlineCode(ticketNo);
        LOG.debug("airlineCode : {}", airlineCode);
        refundTktForm.setAirlineCode(airlineCode);
        String firstTicketNo = getFirstTicketNoWithoutAirline(ticketNo);
        LOG.debug("firstTicketNo : {}", firstTicketNo);
        refundTktForm.setTktNo(firstTicketNo);
        String lastTicketNo = getLastTicketNoWithoutAirline(ticketNo);
        LOG.debug("lastTicketNo : {}", lastTicketNo);
        refundTktForm.setTktNo_end(lastTicketNo);

        refundTktForm.setCommissionRate(0); //代理费
        int ticketSize = getTicketSize(ticketNo);
        LOG.debug("conjunction or ticketSize : {}", ticketSize);
        refundTktForm.setConjunction(String.valueOf(ticketSize));//连票张数

        BigDecimal leftTktPrice = refundTkt.getLeftTktPrice();
        //向前兼容,由于以前的bug引起的
        if (leftTktPrice == null) {
            leftTktPrice = refundTkt.getTktPrice();
        }

        if (refundTkt.isReschedule()) {
            BigDecimal rescheduleGap = refundTkt.getRescheduleGap();
            if (rescheduleGap != null) {
                leftTktPrice = leftTktPrice.add(rescheduleGap);
            }
        }
        double grossRefund = leftTktPrice.doubleValue();

        BigDecimal fee = entity.getRefundFee();
        double deduction = fee.doubleValue();
        if (fee.compareTo(leftTktPrice) > 0) {
            LOG.warn("Refund fee {} greater than ticket price(gross refund){}, setting refund fee and gross refund to 0 to generate refund No", fee, leftTktPrice);
            deduction = grossRefund = 0;
        }

        LOG.info("Generating refund No grossRefund(ticket price value):{}", grossRefund);
        refundTktForm.setGrossRefund(grossRefund); //退票时剩余的票面价(不含税)
        LOG.debug("deduction or refund fee : {}", deduction);
        refundTktForm.setDeduction(deduction); //退票手续费

        refundTktForm.setTaxes(buildTaxs(entity));
//        refundTktForm.setPayMethod(ticketNo);
//        refundTktForm.setCreditcard(currency);
        return refundTktForm;
    }

    private List<Tax> buildTaxs(RefundApplyDto entity) {
        String currency = entity.getCurrency();
        Set<RefundTaxDto> refundTaxs = entity.getRefundTkt().getRefundTaxes();
        return buildTaxs(currency, refundTaxs);
    }

    private List<Tax> buildTaxs(String currency, Set<RefundTaxDto> refundTaxs) {
        Map<String, Tax> taxMap = new HashMap<>(refundTaxs.size(), 1.0f);
        for (RefundTaxDto refundTax : refundTaxs) {
            Tax tax = buildTax(currency, refundTax);
            //如果税费为零, 提交生产退票单会出现异常"CHECK TAX EXCEPTION",所以这里过滤掉
            if (tax.getTax() > 0) {
                String type = tax.getTaxCode();
                //合并相同税种
                if (taxMap.containsKey(type)) {
                    Tax value = taxMap.get(type);
                    Tax newTax = new Tax();
                    newTax.setCurrency(currency);
                    newTax.setTaxCode(type);
                    newTax.setTax(new BigDecimal(String.valueOf(value.getTax())).add(new BigDecimal(String.valueOf(tax.getTax()))).doubleValue());
                    taxMap.put(type, newTax);
                } else {
                    taxMap.put(type, tax);
                }
            } else {
                LOG.warn("Tax {} value is 0", tax.getTaxCode());
            }
        }
        if (taxMap.isEmpty()) {
            LOG.error("Refund tax items are empty");
        }
        return new ArrayList<>(taxMap.values());
    }

    private Tax buildTax(String currency, RefundTaxDto refundTax) {
        Tax tax = new Tax();
        tax.setCurrency(currency);
        String taxType = refundTax.getTaxType();
        LOG.debug("taxType : {}", taxType);
        tax.setTaxCode(taxType);
        BigDecimal taxVa = refundTax.getRefundValue() == null ? BigDecimal.ZERO : refundTax.getRefundValue();
        double taxValue = taxVa.doubleValue();
        LOG.debug("taxValue : {}", taxValue);
        tax.setTax(taxValue);
        return tax;
    }

    private int getTicketSize(String ticketNo) {
        return ticketNo.split("/").length;
    }

    /**
     * 获取航空公司代码
     *
     * @param ticketNo 7811150060465
     * @return 781
     */
    private String getAirlineCode(String ticketNo) {
        return ticketNo.substring(0, 3);
    }

    /**
     * 获取第一个没有带有航空公司代码的票号.
     *
     * @param ticketNo 7811150060465/7811150060466/7811150060467
     * @return 1150060465
     */
    private String getFirstTicketNoWithoutAirline(String ticketNo) {
        String firstTicketNo = ticketNo;
        if (ticketNo.contains("/")) {
            firstTicketNo = ticketNo.substring(0, ticketNo.indexOf('/'));
        }
        return ticketNoWithAirline(firstTicketNo);
    }

    /**
     * 获取最后一个没有带有航空公司代码的票号.
     *
     * @param ticketNo 7811150060465/7811150060466/7811150060467
     * @return 1150060467
     */
    private String getLastTicketNoWithoutAirline(String ticketNo) {
        String lastTicketNo = ticketNo;
        if (ticketNo.contains("/")) {
            lastTicketNo = ticketNo.substring(ticketNo.lastIndexOf('/') + 1);
        }
        return ticketNoWithAirline(lastTicketNo);
    }

    private String ticketNoWithAirline(String ticketNo) {
        if (ticketNo.contains("-")) {
            return ticketNo.substring(ticketNo.indexOf('-') + 1);
        }
        return ticketNo.substring(3);
    }

    private String getPayMethod(String productOrderNo){
        LOG.info("获取payMethod："+productOrderNo);
        PayProductDto payProductDto=new PayProductDto();
        payProductDto.setProductId(productOrderNo);
        List<PayDto> paydtos = iPayQueryService.getPayDOAndPayProductDOList(payProductDto);
        String payMethod = "";
        if(paydtos!=null && paydtos.size()>0){
            for (PayDto payDto : paydtos) {
                if(payDto.getPaySt() == PaymentStatusEnum.PAY_SUCCESS.getCode()
                        || payDto.getPaySt() == PaymentStatusEnum.RISK_PROCESS.getCode()){
                    payMethod = payDto.getPccode();
                    LOG.info("payMethod为："+payMethod);
                }
            }
        }
        return payMethod;
    }
}
